import 'package:built_collection/built_collection.dart';
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';
import 'package:website.core/core/domain/entities/app_store/app_store_purchased_item.dart';
import 'package:website.core/core/domain/entities/google_play/google_play_purchased_item.dart';
import 'package:website.core/core/domain/entities/web/web_purchase_item.dart';
import 'package:website.core/core/domain/entities/web/web_purchased_item.dart';
import 'package:website.core/core/domain/errors/failures.dart';
import 'package:website.core/core/domain/repositories/purchase_item_repository/repository.dart';
import 'package:website.core/core/domain/repositories/purchased_item_repository/repository.dart';
import 'package:website.core/core/domain/utils/either_extension.dart';
import 'package:website.home.account/purchase_management_fragment/domain/entites/google_play_purchased_subscription_model.dart';
import 'package:website.home.account/purchase_management_fragment/domain/entites/purchased_item_model.dart';
import 'package:website.home.account/purchase_management_fragment/domain/entites/purchased_subscription_model.dart';
import 'package:website.home.account/purchase_management_fragment/domain/helpers/create_purchased_item_models/create_purchased_item_models.dart';

part 'failures.dart';

part 'result.dart';

abstract class GetPurchaseManagementData {
  Future<Either<PurchaseManagementDataGettingFailure, PurchaseManagementDataGettingResult>> call();
}

class GetPurchaseManagementDataImpl implements GetPurchaseManagementData {
  const GetPurchaseManagementDataImpl({
    required CreatePurchasedItemModels createPurchasedItemModels,
    required PurchasedItemRepository purchasedItemRepository,
    required PurchaseItemRepository purchaseItemRepository,
  })  : _createPurchasedItemModels = createPurchasedItemModels,
        _purchaseItemRepository = purchaseItemRepository,
        _purchasedItemRepository = purchasedItemRepository;

  final CreatePurchasedItemModels _createPurchasedItemModels;

  final PurchaseItemRepository _purchaseItemRepository;
  final PurchasedItemRepository _purchasedItemRepository;

  @override
  Future<Either<PurchaseManagementDataGettingFailure, PurchaseManagementDataGettingResult>>
      call() async {
    final futureResults = await Future.wait([
      _purchaseItemRepository.getWebPurchaseItems(),
      _purchasedItemRepository.getPurchasedItems(),
    ]);

    var i = 0;
    final failureOrWebPurchaseItems =
        futureResults[i++] as Either<WebPurchaseItemGettingFailure, BuiltList<WebPurchaseItem>>;
    final purchasedItemGettingResultOrFailure =
        futureResults[i++] as Either<PurchasedItemGettingFailure, PurchasedItemGettingResult>;

    WebPurchaseItemGettingFailure? webPurchaseItemGettingFailure;
    PurchasedItemGettingFailure? purchasedItemGettingFailure;

    if (failureOrWebPurchaseItems.isLeft()) {
      webPurchaseItemGettingFailure = failureOrWebPurchaseItems.asLeft();
    }

    if (purchasedItemGettingResultOrFailure.isLeft()) {
      purchasedItemGettingFailure = purchasedItemGettingResultOrFailure.asLeft();
    }

    if (webPurchaseItemGettingFailure != null || purchasedItemGettingFailure != null) {
      if (purchasedItemGettingFailure is UnauthorizedPurchasedItemGettingFailure) {
        const failure = UnauthorizedPurchaseManagementDataGettingFailure();
        return left(failure);
      }

      if (webPurchaseItemGettingFailure is ServerWebPurchaseItemGettingFailure ||
          purchasedItemGettingFailure is ServerPurchasedItemGettingFailure) {
        const failure = ServerPurchaseManagementDataGettingFailure();
        return left(failure);
      }

      if (webPurchaseItemGettingFailure is NetworkWebPurchaseItemGettingFailure ||
          purchasedItemGettingFailure is NetworkPurchasedItemGettingFailure) {
        const failure = NetworkPurchaseManagementDataGettingFailure();
        return left(failure);
      }

      throw UnimplementedError();
    }

    final webPurchaseItems = failureOrWebPurchaseItems.asRight();
    final purchasedItemGettingResult = purchasedItemGettingResultOrFailure.asRight();

    final webPurchaseItemMap = <String, WebPurchaseItem>{};

    for (final webPurchaseItem in webPurchaseItems) {
      webPurchaseItemMap[webPurchaseItem.sku] = webPurchaseItem;
    }

    final webPurchaseItemBuiltMap = webPurchaseItemMap.build();
    final appStorePurchasedItems = purchasedItemGettingResult.appStorePurchasedItems;
    final googlePlayPurchasedItems = purchasedItemGettingResult.googlePlayPurchasedItems;
    final webPurchasedItems = purchasedItemGettingResult.webPurchasedItems;

    final purchasedItemModelCreationResult = _createPurchasedItemModels(
      appStorePurchasedItems: appStorePurchasedItems,
      googlePlayPurchasedItems: googlePlayPurchasedItems,
      webPurchasedItems: webPurchasedItems,
      webPurchaseItemMap: webPurchaseItemBuiltMap,
    );

    final result = PurchaseManagementDataGettingResult(
      appStorePurchasedItems: appStorePurchasedItems,
      googlePlayPurchasedItems: googlePlayPurchasedItems,
      webPurchasedItems: webPurchasedItems,
      webPurchaseItemMap: webPurchaseItemBuiltMap,
      activePurchasedItemModels: purchasedItemModelCreationResult.activePurchasedItemModels,
      pausedGooglePlayPurchasedSubscriptionModels:
          purchasedItemModelCreationResult.pausedGooglePlayPurchasedSubscriptionModels,
      expiredPurchasedSubscriptionModels:
          purchasedItemModelCreationResult.expiredPurchasedSubscriptionModels,
    );

    return right(result);
  }
}
